--- /dev/null
+#! /bin/sh
+
+# This demonstrates a bug where an xs_acknowledge_watch returns
+# EINVAL, because the daemon doesn't track what watch event it sent
+# and relies on it being the "first" watch which has an event.
+# Watches firing after the first event is sent out will change this.
+
+# Create three things to watch.
+echo mkdir /test | ./xs_test
+echo mkdir /test/1 | ./xs_test
+echo mkdir /test/2 | ./xs_test
+echo mkdir /test/3 | ./xs_test
+
+# Watch all three, fire event on 2, read watch, fire event on 1 and 3, ack 2.
+[ "`echo '1 watch /test/1 token1 0
+1 watch /test/2 token2 0
+1 watch /test/3 token3 0
+2 write /test/2 create contents2
+1 waitwatch
+2 write /test/1 create contents1
+2 write /test/3 create contents3
+1 ackwatch token2' | ./xs_test 2>&1`" = "1:/test/2:token2" ]
/* We might get a command while waiting for an ack: this means
* the other end discarded it: we will re-transmit. */
if (type != XS_WATCH_ACK)
- conn->waiting_for_ack = false;
+ conn->waiting_for_ack = NULL;
/* Careful: process_message may free connection. We detach
* "in" beforehand and allocate the new buffer to avoid
if (conn->waiting_reply) {
conn->out = conn->waiting_reply;
conn->waiting_reply = NULL;
- conn->waiting_for_ack = false;
+ conn->waiting_for_ack = NULL;
return;
}
return;
/* If we decide to cancel, we will reset this. */
- conn->waiting_for_ack = true;
+ conn->waiting_for_ack = event->watches[0];
/* If we deleted /foo and they're watching /foo/bar, that's what we
* tell them has changed. */
if (!conn->waiting_for_ack)
return send_error(conn, ENOENT);
- event = get_first_event(conn);
- if (!streq(event->watches[0]->token, token))
+ event = list_top(&conn->waiting_for_ack->events,
+ struct watch_event, list);
+ assert(event->watches[0] == conn->waiting_for_ack);
+ if (!streq(conn->waiting_for_ack->token, token)) {
+ /* They're confused: this will cause us to send event again */
+ conn->waiting_for_ack = NULL;
return send_error(conn, EINVAL);
+ }
move_event_onwards(event);
- conn->waiting_for_ack = false;
+ conn->waiting_for_ack = NULL;
return send_ack(conn, XS_WATCH_ACK);
}